module spsr(
        input           i_clk,

        input   [ 4:0]  i_mode,

        input           i_we,
        input   [ 4:0]  i_wa_mode_exc,
        input           i_wa_exc,
        input   [31:0]  i_d,

        output  [31:0]  o_q
);

reg [11:0] spsr_fiq;
reg [11:0] spsr_irq;
reg [11:0] spsr_svc;
reg [11:0] spsr_abt;
reg [11:0] spsr_und;

wire fiqbank_noexc;
wire irqbank_noexc;
wire svcbank_noexc;
wire abtbank_noexc;
wire undbank_noexc;

wire fiqbank_exc;
wire irqbank_exc;
wire svcbank_exc;
wire abtbank_exc;
wire undbank_exc;

wire spsr_fiq_we;
wire spsr_irq_we;
wire spsr_svc_we;
wire spsr_abt_we;
wire spsr_und_we;

wire [11:0] d, q;

// verilator lint_off PINCONNECTEMPTY

mode_decoder u_mode_decoder_noexc(
        .i_mode(i_mode),
        .o_usrbank(),
        .o_fiqbank(fiqbank_noexc),
        .o_irqbank(irqbank_noexc),
        .o_svcbank(svcbank_noexc),
        .o_abtbank(abtbank_noexc),
        .o_undbank(undbank_noexc)
);

mode_decoder u_mode_decoder_exc(
        .i_mode(i_wa_mode_exc),
        .o_usrbank(),
        .o_fiqbank(fiqbank_exc),
        .o_irqbank(irqbank_exc),
        .o_svcbank(svcbank_exc),
        .o_abtbank(abtbank_exc),
        .o_undbank(undbank_exc)
);

// verilator lint_on PINCONNECTEMPTY

assign d = {i_d[31:28], i_d[8:6], i_d[4:0]};
assign q =
        {12{fiqbank_noexc}} & spsr_fiq |
        {12{irqbank_noexc}} & spsr_irq |
        {12{svcbank_noexc}} & spsr_svc |
        {12{abtbank_noexc}} & spsr_abt |
        {12{undbank_noexc}} & spsr_und ;

assign o_q = {q[11:8], 19'b0, q[7:5], 1'b0, q[4:0]};

assign spsr_fiq_we = i_we & ( i_wa_exc ? fiqbank_exc : fiqbank_noexc ) ;
assign spsr_irq_we = i_we & ( i_wa_exc ? irqbank_exc : irqbank_noexc ) ;
assign spsr_svc_we = i_we & ( i_wa_exc ? svcbank_exc : svcbank_noexc ) ;
assign spsr_abt_we = i_we & ( i_wa_exc ? abtbank_exc : abtbank_noexc ) ;
assign spsr_und_we = i_we & ( i_wa_exc ? undbank_exc : undbank_noexc ) ;

always @(posedge i_clk) begin
        if (spsr_fiq_we) spsr_fiq <= d;
        if (spsr_irq_we) spsr_irq <= d;
        if (spsr_svc_we) spsr_svc <= d;
        if (spsr_abt_we) spsr_abt <= d;
        if (spsr_und_we) spsr_und <= d;
end

`ifndef SYNTHESIS

reg trace;

initial trace = $test$plusargs("trace") != 0;

always @(posedge i_clk) begin
        if (trace) begin
                if (spsr_fiq_we) $display("%%spsr_fiq=%x", i_d);
                if (spsr_irq_we) $display("%%spsr_irq=%x", i_d);
                if (spsr_svc_we) $display("%%spsr_svc=%x", i_d);
                if (spsr_abt_we) $display("%%spsr_abt=%x", i_d);
                if (spsr_und_we) $display("%%spsr_und=%x", i_d);
        end
end

`endif

endmodule
